`timescale 1ns / 1ps 
/**
 ******************************************************************************
 * @file    template_m_axi_s.v
 * @author  KEN
 * @version V1.0
 * @date    Jul. 2nd, 2020
 * @brief   Master AXI4 Interface(Simplified) Template
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT 2020 K'sP</center></h2>
 ******************************************************************************
 */

/*Template Start*/
/*
 
reg WENABLE;
wire WBUSY;
wire WERR;
reg RENABLE;
wire RBUSY;
wire RERR;

reg [(C_AXI_ADDR_WIDTH - 1): 0] MEM_WADDR_BASE;
reg [(C_AXI_ADDR_WIDTH - 1): 0] MEM_RADDR_BASE;
reg [31: 0] MEM_WLEN;
reg [31: 0] MEM_RLEN;
reg [(8 * C_MEM_BUFFER_SIZE - 1): 0] MEM_WVAL;
wire [(8 * C_MEM_BUFFER_SIZE - 1): 0] MEM_RVAL;

wire axi_aclk;
wire axi_aresetn;
wire [(C_AXI_ADDR_WIDTH - 1): 0] axi_awaddr;
wire [7: 0] axi_awlen;
wire [2: 0] axi_awsize;
wire [1: 0] axi_awburst;
wire axi_awlock;
wire [3: 0] axi_awcache;
wire [2: 0] axi_awprot;
wire [3: 0] axi_awqos;
wire axi_awvalid;
wire axi_awready;
wire [(C_AXI_DATA_WIDTH - 1): 0] axi_wdata;
wire [(C_AXI_DATA_WIDTH / 8 - 1): 0] axi_wstrb;
wire axi_wlast;
wire axi_wvalid;
wire axi_wready;
wire [1: 0] axi_bresp;
wire axi_bvalid;
wire axi_bready;
wire [(C_AXI_ADDR_WIDTH - 1): 0] axi_araddr;
wire [7: 0] axi_arlen;
wire [2: 0] axi_arsize;
wire [1: 0] axi_arburst;
wire axi_arlock;
wire [3: 0] axi_arcache;
wire [2: 0] axi_arprot;
wire [3: 0] axi_arqos;
wire axi_arvalid;
wire axi_arready;
wire [(C_AXI_DATA_WIDTH - 1): 0] axi_rdata;
wire [1: 0] axi_rresp;
wire axi_rlast;
wire axi_rvalid;
wire axi_rready;

template_m_axi_s
	#
	(
		.C_MEM_BUFFER_SIZE(C_MEM_BUFFER_SIZE),
		.C_AXI_MAX_BURST_LENGTH(C_AXI_MAX_BURST_LENGTH),
		.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
		.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH)
	)
	template_m_axi_inst
	(
		.WENABLE(WENABLE),
		.WBUSY(WBUSY),
		.WERR(WERR),
		.RENABLE(RENABLE),
		.RBUSY(RBUSY),
		.RERR(RERR),

		.MEM_WADDR_BASE(MEM_WADDR_BASE),
		.MEM_RADDR_BASE(MEM_RADDR_BASE),
		.MEM_WLEN(MEM_WLEN),
		.MEM_RLEN(MEM_RLEN),
		.MEM_WVAL(MEM_WVAL),
		.MEM_RVAL(MEM_RVAL),

		.m_axi_aclk(axi_aclk),
		.m_axi_aresetn(axi_aresetn),
		.m_axi_awaddr(axi_awaddr),
		.m_axi_awlen(axi_awlen),
		.m_axi_awsize(axi_awsize),
		.m_axi_awburst(axi_awburst),
		.m_axi_awlock(axi_awlock),
		.m_axi_awcache(axi_awcache),
		.m_axi_awprot(axi_awprot),
		.m_axi_awqos(axi_awqos),
		.m_axi_awvalid(axi_awvalid),
		.m_axi_awready(axi_awready),
		.m_axi_wdata(axi_wdata),
		.m_axi_wstrb(axi_wstrb),
		.m_axi_wlast(axi_wlast),
		.m_axi_wvalid(axi_wvalid),
		.m_axi_wready(axi_wready),
		.m_axi_bresp(axi_bresp),
		.m_axi_bvalid(axi_bvalid),
		.m_axi_bready(axi_bready),
		.m_axi_araddr(axi_araddr),
		.m_axi_arlen(axi_arlen),
		.m_axi_arsize(axi_arsize),
		.m_axi_arburst(axi_arburst),
		.m_axi_arlock(axi_arlock),
		.m_axi_arcache(axi_arcache),
		.m_axi_arprot(axi_arprot),
		.m_axi_arqos(axi_arqos),
		.m_axi_arvalid(axi_arvalid),
		.m_axi_arready(axi_arready),
		.m_axi_rdata(axi_rdata),
		.m_axi_rresp(axi_rresp),
		.m_axi_rlast(axi_rlast),
		.m_axi_rvalid(axi_rvalid),
		.m_axi_rready(axi_rready)
	);
*/ 
/*Template End*/
`define AXI_RESPOENSE_OKAY 2'b00
`define AXI_RESPOENSE_EXOKAY 2'b01
`define AXI_RESPOENSE_SLVERR 2'b10
`define AXI_RESPOENSE_DECERR 2'b11

`define AXI_BURST_TYPE_FIXED 2'b00
`define AXI_BURST_TYPE_INCR 2'b01
`define AXI_BURST_TYPE_WRAP 2'b10

`define AXI_ACCESS_TYPE_NORMAL 1'b0
`define AXI_ACCESS_TYPE_EXCLUSIVE 1'b1

module template_m_axi_s
	   #
	   (
		   parameter integer C_MEM_BUFFER_SIZE = 16,
		   parameter integer C_AXI_MAX_BURST_LENGTH = 256,
		   parameter integer C_AXI_ADDR_WIDTH = 32,
		   parameter integer C_AXI_DATA_WIDTH = 32
	   )
	   (
		   input wire WENABLE,
		   output wire WBUSY,
		   output wire WERR,
		   input wire RENABLE,
		   output wire RBUSY,
		   output wire RERR,

		   input wire [(C_AXI_ADDR_WIDTH - 1): 0] MEM_WADDR_BASE,
		   input wire [(C_AXI_ADDR_WIDTH - 1): 0] MEM_RADDR_BASE,
		   input wire [31: 0] MEM_WLEN,
		   input wire [31: 0] MEM_RLEN,
		   input wire [(8 * C_MEM_BUFFER_SIZE - 1): 0] MEM_WVAL,
		   output wire [(8 * C_MEM_BUFFER_SIZE - 1): 0] MEM_RVAL,

		   /*Master AXI4 Interface*/
		   //Global ACLK
		   (* X_INTERFACE_INFO = "xilinx.com:signal:clock:1.0 m_axi_aclk CLK" *)
		   (* X_INTERFACE_PARAMETER = "ASSOCIATED_BUSIF m_axi, ASSOCIATED_RESET m_axi_aresetn" *)
		   input wire m_axi_aclk,
		   //Global ARESETn
		   (* X_INTERFACE_INFO = "xilinx.com:signal:reset:1.0 m_axi_aresetn RST" *)
		   (* X_INTERFACE_PARAMETER = "POLARITY ACTIVE_LOW" *)
		   input wire m_axi_aresetn,

		   //Write address channel.
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi AWADDR" *)
		   output wire [(C_AXI_ADDR_WIDTH - 1): 0] m_axi_awaddr,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi AWLEN" *)
		   output wire [7: 0] m_axi_awlen,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi AWSIZE" *)
		   output wire [2: 0] m_axi_awsize,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi AWBURST" *)
		   output wire [1: 0] m_axi_awburst,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi AWLOCK" *)
		   output wire m_axi_awlock,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi AWCACHE" *)
		   output wire [3: 0] m_axi_awcache,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi AWPROT" *)
		   output wire [2: 0] m_axi_awprot,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi AWQOS" *)
		   output wire [3: 0] m_axi_awqos,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi AWVALID" *)
		   output wire m_axi_awvalid,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi AWREADY" *)
		   input wire m_axi_awready,

		   //Write data channel.
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi WDATA" *)
		   output wire [(C_AXI_DATA_WIDTH - 1): 0] m_axi_wdata,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi WSTRB" *)
		   output wire [(C_AXI_DATA_WIDTH / 8 - 1): 0] m_axi_wstrb,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi WLAST" *)
		   output wire m_axi_wlast,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi WVALID" *)
		   output wire m_axi_wvalid,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi WREADY" *)
		   input wire m_axi_wready,

		   //Write response channel.
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi BRESP" *)
		   input wire [1: 0] m_axi_bresp,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi BVALID" *)
		   input wire m_axi_bvalid,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi BREADY" *)
		   output wire m_axi_bready,

		   //Read address channel.
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi ARADDR" *)
		   output wire [(C_AXI_ADDR_WIDTH - 1): 0] m_axi_araddr,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi ARLEN" *)
		   output wire [7: 0] m_axi_arlen,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi ARSIZE" *)
		   output wire [2: 0] m_axi_arsize,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi ARBURST" *)
		   output wire [1: 0] m_axi_arburst,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi ARLOCK" *)
		   output wire m_axi_arlock,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi ARCACHE" *)
		   output wire [3: 0] m_axi_arcache,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi ARPROT" *)
		   output wire [2: 0] m_axi_arprot,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi ARQOS" *)
		   output wire [3: 0] m_axi_arqos,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi ARVALID" *)
		   output wire m_axi_arvalid,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi ARREADY" *)
		   input wire m_axi_arready,

		   //Read data channel.
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi RDATA" *)
		   input wire [(C_AXI_DATA_WIDTH - 1): 0] m_axi_rdata,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi RRESP" *)
		   input wire [1: 0] m_axi_rresp,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi RLAST" *)
		   input wire m_axi_rlast,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi RVALID" *)
		   input wire m_axi_rvalid,
		   (* X_INTERFACE_INFO = "xilinx.com:interface:aximm:1.0 m_axi RREADY" *)
		   output wire m_axi_rready
	   );

/*Write address channel Ports Registers*/
reg [(C_AXI_ADDR_WIDTH - 1): 0] awaddr_r;
reg [7: 0] awlen_r;
reg [2: 0] awsize_r;
reg [1: 0] awburst_r;
reg awlock_r;
reg [3: 0] awcache_r;
reg [2: 0] awprot_r;
reg [3: 0] awqos_r;
reg awvalid_r;

assign m_axi_awaddr = awaddr_r;
assign m_axi_awlen = awlen_r;
assign m_axi_awsize = awsize_r;
assign m_axi_awburst = awburst_r;
assign m_axi_awlock = awlock_r;
assign m_axi_awcache = awcache_r;
assign m_axi_awprot = awprot_r;
assign m_axi_awqos = awqos_r;
assign m_axi_awvalid = awvalid_r;

/*Write data channel Ports Registers*/
reg [(C_AXI_DATA_WIDTH - 1): 0] wdata_r;
reg [(C_AXI_DATA_WIDTH / 8 - 1): 0] wstrb_r;
reg wlast_r;
reg wvalid_r;

assign m_axi_wdata = wdata_r;
assign m_axi_wstrb = wstrb_r;
assign m_axi_wlast = wlast_r;
assign m_axi_wvalid = wvalid_r;

/*Write response channel Ports Registers*/
reg bready_r;

assign m_axi_bready = bready_r;

/*Read address channel Ports Registers*/
reg [(C_AXI_ADDR_WIDTH - 1): 0] araddr_r;
reg [7: 0] arlen_r;
reg [2: 0] arsize_r;
reg [1: 0] arburst_r;
reg arlcok_r;
reg [3: 0] arcache_r;
reg [2: 0] arprot_r;
reg [3: 0] arqos_r;
reg arvalid_r;

assign m_axi_araddr = araddr_r;
assign m_axi_arlen = arlen_r;
assign m_axi_arsize = arsize_r;
assign m_axi_arburst = arburst_r;
assign m_axi_arlock = arlcok_r;
assign m_axi_arcache = arcache_r;
assign m_axi_arprot = arprot_r;
assign m_axi_arqos = arqos_r;
assign m_axi_arvalid = arvalid_r;

/*Read data channel Ports Registers*/
reg rready_r;

assign m_axi_rready = rready_r;

/*Assistant parameter*/
localparam integer Data_Bus_Bytes = C_AXI_DATA_WIDTH / 8;

function [7: 0] log2(input [31: 0] num);
	reg [31: 0] temp;
	begin
		for (temp = num, log2 = 0;temp > 1;log2 = log2 + 1)
		begin
			temp = temp >> 1;
		end
	end

endfunction

function [(C_AXI_ADDR_WIDTH - 1): 0] DataBusAlign(input [(C_AXI_ADDR_WIDTH - 1): 0] addr);
	begin
		DataBusAlign = addr - (addr % (C_AXI_DATA_WIDTH / 8));
	end

endfunction

/*Write Process*/
reg wbusy_r;
reg werr_r;
wire [(C_AXI_DATA_WIDTH - 1): 0] mem_wval_ar [(C_MEM_BUFFER_SIZE / Data_Bus_Bytes - 1): 0];

assign WBUSY = wbusy_r;
assign WERR = werr_r;
generate
	genvar wari;

	for (wari = 0;wari < C_MEM_BUFFER_SIZE / Data_Bus_Bytes;wari = wari + 1)
	begin : war
		assign mem_wval_ar[wari] = MEM_WVAL[(wari * C_AXI_DATA_WIDTH) +: C_AXI_DATA_WIDTH];
	end

endgenerate

localparam MEM_WSTATE_IDLE = 'd0;
localparam MEM_WSTATE_START = 'd1;
localparam MEM_WSTATE_AWVALID = 'd2;
localparam MEM_WSTATE_AWREADY = 'd3;
localparam MEM_WSTATE_WREADY = 'd4;
localparam MEM_WSTATE_BREADY = 'd5;
localparam MEM_WSTATE_END = 'd6;
reg [3: 0] mem_wstate_r;

reg [31: 0] mem_transed;
reg [31: 0] wburst_index;

wire [31: 0] WMEM_TOTAL = (MEM_WLEN + Data_Bus_Bytes - 1) / Data_Bus_Bytes;
wire [31: 0] WMEM_AVAILABLE = ((WMEM_TOTAL - mem_transed) > C_AXI_MAX_BURST_LENGTH) ?
	 C_AXI_MAX_BURST_LENGTH : (WMEM_TOTAL - mem_transed);

always@( * )
begin
	if (mem_transed < WMEM_TOTAL)
	begin
		wdata_r <= mem_wval_ar[mem_transed];
	end
	else
	begin
		wdata_r <= 0;
	end
end

always@(posedge m_axi_aclk or negedge m_axi_aresetn)
begin
	if (~m_axi_aresetn)
	begin
		wbusy_r <= 1'b0;
		werr_r <= 1'b0;

		awaddr_r <= 0;
		awlen_r <= 0;

		awsize_r <= log2(Data_Bus_Bytes);
		awburst_r <= `AXI_BURST_TYPE_INCR;
		awlock_r <= `AXI_ACCESS_TYPE_NORMAL;
		awcache_r <= 4'b0011;
		awprot_r <= 3'b000;
		awqos_r <= 4'b0000;

		awvalid_r <= 1'b0;

		wstrb_r <= (1 << Data_Bus_Bytes) - 1;
		wlast_r <= 1'b0;
		wvalid_r <= 1'b0;

		bready_r <= 1'b1;

		mem_wstate_r <= MEM_WSTATE_IDLE;

		mem_transed <= 0;
		wburst_index <= 0;
	end
	else
	begin

		case (mem_wstate_r)
			MEM_WSTATE_IDLE:
			begin
				if (WENABLE == 1'b0)
				begin
					mem_wstate_r <= MEM_WSTATE_START;
				end
			end

			MEM_WSTATE_START:
			begin
				if ((WENABLE == 1'b1) && (MEM_WLEN > 0) && (MEM_WLEN <= C_MEM_BUFFER_SIZE))
				begin
					mem_wstate_r <= MEM_WSTATE_AWVALID;

					wbusy_r <= 1'b1;
					werr_r <= 1'b0;

					mem_transed <= 0;

					awaddr_r <= DataBusAlign(MEM_WADDR_BASE);
				end
			end

			MEM_WSTATE_AWVALID:
			begin
				mem_wstate_r <= MEM_WSTATE_AWREADY;

				awvalid_r <= 1'b1;

				//4KB Boundary Detect and Burst-size limitation
				if (('h1000 - awaddr_r[11: 0]) < (WMEM_AVAILABLE * Data_Bus_Bytes))
				begin
					awlen_r <= ( ('h1000 - awaddr_r[11: 0]) + Data_Bus_Bytes - 1 ) / Data_Bus_Bytes - 1;
				end
				else
				begin
					awlen_r <= WMEM_AVAILABLE - 1;
				end

				wburst_index <= 0;
			end

			MEM_WSTATE_AWREADY:
			begin
				if (m_axi_awready)
				begin
					mem_wstate_r <= MEM_WSTATE_WREADY;

					awvalid_r <= 1'b0;

					wvalid_r <= 1'b1;

					if (wburst_index == m_axi_awlen)
					begin
						wlast_r <= 1'b1;
					end
					else
					begin
						wlast_r <= 1'b0;
						wburst_index <= wburst_index + 1;
					end
				end
			end

			MEM_WSTATE_WREADY:
			begin
				if (m_axi_wready)
				begin
					if (m_axi_wlast)
					begin
						mem_wstate_r <= MEM_WSTATE_BREADY;

						wvalid_r <= 1'b0;
						wlast_r <= 1'b0;
					end
					else
					begin
						if (wburst_index == m_axi_awlen)
						begin
							wlast_r <= 1'b1;
						end

						wburst_index <= wburst_index + 1;
					end

					mem_transed <= mem_transed + 1;
				end
			end

			MEM_WSTATE_BREADY:
			begin
				if (m_axi_bvalid)
				begin
					mem_wstate_r <= MEM_WSTATE_END;

					if (m_axi_bresp != `AXI_RESPOENSE_OKAY)
					begin
						werr_r <= 1'b1;
						mem_transed <= WMEM_TOTAL;
					end

					bready_r <= 1'b0;
				end
			end

			MEM_WSTATE_END:
			begin
				bready_r <= 1'b1;

				if (mem_transed == WMEM_TOTAL)
				begin
					mem_wstate_r <= MEM_WSTATE_IDLE;

					wbusy_r <= 1'b0;

					awaddr_r <= 0;
					awlen_r <= 0;
				end
				else
				begin
					mem_wstate_r <= MEM_WSTATE_AWVALID;

					awaddr_r <= DataBusAlign(MEM_WADDR_BASE) + mem_transed * Data_Bus_Bytes;
				end
			end

			default:
			begin
				mem_wstate_r <= MEM_WSTATE_IDLE;
			end

		endcase

	end
end

/*Read Process*/
reg rbusy_r;
reg rerr_r;
reg [(C_AXI_DATA_WIDTH - 1): 0] mem_rval_ar[(C_MEM_BUFFER_SIZE / Data_Bus_Bytes - 1): 0];

assign RBUSY = rbusy_r;
assign RERR = rerr_r;

generate
	genvar rari;

	for (rari = 0;rari < C_MEM_BUFFER_SIZE / Data_Bus_Bytes;rari = rari + 1)
	begin : rar
		assign MEM_RVAL[(rari * C_AXI_DATA_WIDTH) +: C_AXI_DATA_WIDTH] = mem_rval_ar[rari];
	end

endgenerate

localparam MEM_RSTATE_IDLE = 'd0;
localparam MEM_RSTATE_START = 'd1;
localparam MEM_RSTATE_ARVALID = 'd2;
localparam MEM_RSTATE_ARREADY = 'd3;
localparam MEM_RSTATE_RVALID = 'd4;
localparam MEM_RSTATE_END = 'd5;
reg [3: 0] mem_rstate_r;

reg [31: 0] mem_recved;
reg [31: 0] rburst_index;

wire [31: 0] RMEM_TOTAL = (MEM_RLEN + Data_Bus_Bytes - 1) / Data_Bus_Bytes;
wire [31: 0] RMEM_AVAILABLE = ((RMEM_TOTAL - mem_recved) > C_AXI_MAX_BURST_LENGTH) ?
	 C_AXI_MAX_BURST_LENGTH : (RMEM_TOTAL - mem_recved);

integer mem_index;

always@(posedge m_axi_aclk or negedge m_axi_aresetn)
begin
	if (~m_axi_aresetn)
	begin
		rbusy_r <= 1'b0;
		rerr_r <= 1'b0;

		for (mem_index = 0;mem_index < C_MEM_BUFFER_SIZE / Data_Bus_Bytes;mem_index = mem_index + 1)
		begin
			mem_rval_ar[mem_index] <= 0;
		end

		araddr_r <= 0;
		arlen_r <= 0;

		arsize_r <= log2(Data_Bus_Bytes);
		arburst_r <= `AXI_BURST_TYPE_INCR;
		arlcok_r <= `AXI_ACCESS_TYPE_NORMAL;
		arcache_r <= 4'b0011;
		arprot_r <= 3'b000;
		arqos_r <= 4'b0000;

		arvalid_r <= 1'b0;

		rready_r <= 1'b1;

		mem_rstate_r <= MEM_RSTATE_IDLE;

		mem_recved <= 0;
		rburst_index <= 0;

	end
	else
	begin
		case (mem_rstate_r)
			MEM_RSTATE_IDLE :
			begin
				if (RENABLE == 1'b0)
				begin
					mem_rstate_r <= MEM_RSTATE_START;
				end
			end

			MEM_RSTATE_START :
			begin
				if ((RENABLE == 1'b1) && (MEM_RLEN > 0) && (MEM_RLEN <= C_MEM_BUFFER_SIZE))
				begin
					mem_rstate_r <= MEM_RSTATE_ARVALID;

					rbusy_r <= 1'b1;
					rerr_r <= 1'b0;

					for (mem_index = 0;mem_index < C_MEM_BUFFER_SIZE / Data_Bus_Bytes;mem_index = mem_index + 1)
					begin
						mem_rval_ar[mem_index] <= 0;
					end

					mem_recved <= 0;

					araddr_r <= DataBusAlign(MEM_RADDR_BASE);

				end
			end

			MEM_RSTATE_ARVALID:
			begin
				mem_rstate_r <= MEM_RSTATE_ARREADY;

				arvalid_r <= 1'b1;

				//4KB Boundary Detect and Burst-size limitation
				if (('h1000 - araddr_r[11: 0]) < (RMEM_AVAILABLE * Data_Bus_Bytes))
				begin
					arlen_r <= ( ('h1000 - araddr_r[11: 0]) + Data_Bus_Bytes - 1 ) / Data_Bus_Bytes - 1;
				end
				else
				begin
					arlen_r <= RMEM_AVAILABLE - 1;
				end

				rburst_index <= 0;

			end

			MEM_RSTATE_ARREADY:
			begin
				if (m_axi_arready)
				begin
					mem_rstate_r <= MEM_RSTATE_RVALID;

					arvalid_r <= 1'b0;
				end
			end

			MEM_RSTATE_RVALID :
			begin
				if (m_axi_rvalid)
				begin
					if (m_axi_rresp != `AXI_RESPOENSE_OKAY)
					begin
						mem_rstate_r <= MEM_RSTATE_END;
						rready_r <= 1'b0;

						rerr_r <= 1'b1;
						mem_recved <= RMEM_TOTAL;
					end
					else
					begin
						mem_rval_ar[mem_recved] <= m_axi_rdata;

						if (rburst_index == m_axi_arlen)
						begin
							mem_rstate_r <= MEM_RSTATE_END;

							rready_r <= 1'b0;

							if (m_axi_rlast == 0)
							begin
								rerr_r <= 1'b1;
							end
						end

						rburst_index <= rburst_index + 1;
						mem_recved <= mem_recved + 1;
					end
				end
			end

			MEM_RSTATE_END :
			begin
				rready_r <= 1'b1;

				if (mem_recved == RMEM_TOTAL)
				begin
					mem_rstate_r <= MEM_RSTATE_IDLE;

					rbusy_r <= 1'b0;

					araddr_r <= 0;
					arlen_r <= 0;
				end
				else
				begin
					mem_rstate_r <= MEM_RSTATE_ARVALID;
					
					//Read Aligned Address
					araddr_r <= DataBusAlign(MEM_RADDR_BASE) + mem_recved * Data_Bus_Bytes;
				end
			end
			
			default:
			begin
				mem_rstate_r <= MEM_RSTATE_IDLE;
			end

		endcase
	end
end


endmodule